package lzq.aop.config;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.stereotype.Component;

@Component
public class JdbcTemplate {
	
	@Autowired
	private DataSource dataSource;
	
	
	
	
	public DataSource getDataSource() {
		return dataSource;
	}


	public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
			throws DataAccessException {

		Connection con = DataSourceUtils.getConnection(dataSource);
		PreparedStatement ps = null;
		try {
			Connection conToUse = con;
			ps = psc.createPreparedStatement(conToUse);
			T result = action.doInPreparedStatement(ps);
			return result;
		}
		catch (SQLException ex) {
			// Release Connection early, to avoid potential connection pool deadlock
			// in the case when the exception translator hasn't been initialized yet.
			closeStatement(ps);
			ps = null;
			DataSourceUtils.close();
			con = null;
			throw new RuntimeException("执行语句"+getSql(action)+"异常", ex);
		}
//		finally {
//			closeStatement(ps);
//			DataSourceUtils.close();
//		}
	}
	
	
	public <T> T execute(StatementCallback<T> action){

		Connection conToUse = DataSourceUtils.getConnection(dataSource);
		Statement stmt = null;
		try {
			stmt = conToUse.createStatement();
			Statement stmtToUse = stmt;
			T result = action.doInStatement(stmtToUse);
			return result;
		}
		catch (SQLException ex) {
			// Release Connection early, to avoid potential connection pool deadlock
			// in the case when the exception translator hasn't been initialized yet.
			closeStatement(stmt);
			stmt = null;
			DataSourceUtils.close();
			conToUse = null;
			throw new RuntimeException("执行语句"+getSql(action)+"异常", ex);
		}
		finally {
			closeStatement(stmt);
			DataSourceUtils.close();
		}
	}
	
	
	public int update(final String sql)  {
		class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
			@Override
			public Integer doInStatement(Statement stmt) throws SQLException {
				int rows = stmt.executeUpdate(sql);
				return rows;
			}
			@Override
			public String getSql() {
				return sql;
			}
		}
		return execute(new UpdateStatementCallback());
	}
	
	
	
	
	public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
		class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
			@Override
			public T doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = null;
				try {
					rs = stmt.executeQuery(sql);
					ResultSet rsToUse = rs;
					return rse.extractData(rsToUse);
				}
				finally {
					JdbcUtils.closeResultSet(rs);
				}
			}
			@Override
			public String getSql() {
				return sql;
			}
		}
		return execute(new QueryStatementCallback());
	}
	
	
	public static void closeStatement(Statement stmt) {
		System.out.println("关闭statemet");
		if (stmt != null) {
			try {
				stmt.close();
			}
			catch (SQLException ex) {
				ex.printStackTrace();
			}
			catch (Throwable ex) {
				ex.printStackTrace();
			}
		}
	}
	
	private static String getSql(Object sqlProvider) {
		if (sqlProvider instanceof SqlProvider) {
			return ((SqlProvider) sqlProvider).getSql();
		}
		else {
			return null;
		}
	}
}
